package manage.modules.role.service.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import manage.commons.utils.Pager;
import manage.commons.utils.TableNameUtil;
import manage.modules.BaseService;
import manage.modules.dept.model.Dept;
import manage.modules.dept.model.GroupOfDept;
import manage.modules.group.model.Group;
import manage.modules.group.model.WorkerOfGroup;
import manage.modules.rbac.model.ActionOfRole;
import manage.modules.rbac.model.MenuOfRole;
import manage.modules.role.model.Role;
import manage.modules.role.service.RoleService;
import manage.modules.worker.model.Worker;
import manage.modules.worker.model.WorkerOfRole;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.jdbc.core.simple.ParameterizedBeanPropertyRowMapper;
import org.springframework.jdbc.core.simple.ParameterizedRowMapper;

public class RoleServiceImpl implements RoleService {
	private static final String ROLE_TABLE_PRIMARY = "roleId";
	private static final String ROLE_CACHE_KEY = "allRole";
	private BaseService baseService;
	private ParameterizedRowMapper<Role> rowMapper = ParameterizedBeanPropertyRowMapper
			.newInstance(getClazz());

	@Override
	public Role select(Integer roleId) {
		return baseService.select(ROLE_TABLE_PRIMARY, roleId, getClazz());
	}

	@Override
	public int insert(Role role) {
		int count = baseService.insert(role);
		clearCacheByCount(count);
		return count;
	}

	@Override
	public int update(Role role) {
		int count = baseService.updateFields(ROLE_TABLE_PRIMARY,
				role.getRoleId(), role);
		clearCacheByCount(count);
		return count;
	}

	@Override
	public int delete(Integer roleId) {
		int count = baseService.delete(ROLE_TABLE_PRIMARY, roleId, getClazz());
		deleteMenuOfRoleByRoleId(roleId);
		deleteWorkerOfRoleByRoleId(roleId);
		deleteActionOfRoleByRoleId(roleId);
		clearCacheByCount(count);
		return count;
	}

	@Override
	public int deleteActionOfRoleByRoleId(Integer roleId) {
		return baseService.delete(ROLE_TABLE_PRIMARY, roleId,
				ActionOfRole.class);
	}

	@Override
	public int deleteWorkerOfRoleByRoleId(Integer roleId) {
		return baseService.delete(ROLE_TABLE_PRIMARY, roleId,
				WorkerOfRole.class);
	}

	@Override
	public int deleteMenuOfRoleByRoleId(Integer roleId) {
		return baseService.delete(ROLE_TABLE_PRIMARY, roleId, MenuOfRole.class);
	}

	@Override
	public List<Role> listAll() {
		List<Role> allRole = (List<Role>) baseService.getListByCache(
				ROLE_CACHE_KEY, getClazz());
		if (CollectionUtils.isEmpty(allRole)) {
			allRole = baseService.listAll(getClazz());
			if (CollectionUtils.isNotEmpty(allRole)) {
				baseService.setCache(ROLE_CACHE_KEY, allRole);
			}
		}
		return allRole;
	}

	@Override
	public boolean exists(Integer roleId) {
		return baseService.exists(ROLE_TABLE_PRIMARY, roleId, getClazz());
	}

	@Override
	public Long getCountOfAll() {
		return baseService.countOfAll(getClazz());
	}

	@Override
	public void query(Role role, Pager<Role> pager) {
		StringBuilder querySql = new StringBuilder(1024);
		querySql.append("select * from "
				+ TableNameUtil.getTableName(getClazz()) + " where 1=1");
		if (role != null) {
			if (null != role.getRoleId()) {
				querySql.append(" and roleId =" + role.getRoleId());
			}
			if (StringUtils.isNotBlank(role.getRoleName())) {
				querySql.append(" and roleName like '%" + role.getRoleName()
						+ "%'");
			}
			if (null != role.getOrderNo()) {
				querySql.append(" and orderNo =" + role.getOrderNo());
			}
			pager.setRowCount(baseService.getJdbcOperations().queryForLong(
					baseService.getCountSql(querySql.toString())));
			querySql.append(" limit ?,?");
			pager.setList(baseService.getJdbcOperations().query(
					querySql.toString(), rowMapper, pager.getRowOffset(),
					pager.getPageSize()));
		}

	}

	@Override
	public void query(Map<String, String> param,
			Pager<Map<String, Object>> pager) {
		StringBuilder sql = new StringBuilder(1000);
		sql.append(
				"select distinct w.* from  "
						+ TableNameUtil.getTableName(Worker.class) + " w ")
				.append(" left join "
						+ TableNameUtil.getTableName(WorkerOfGroup.class)
						+ " wg on wg.workerId=w.workerId")
				.append(" left join "
						+ TableNameUtil.getTableName(GroupOfDept.class)
						+ " gd on gd.deptId=wg.groupId")
				.append(" left join "
						+ TableNameUtil.getTableName(WorkerOfRole.class)
						+ " wr on w.workerId=wr.workerId")
				.append(" where 1 = 1");
		if (MapUtils.isNotEmpty(param)) {
			if (StringUtils.isNotBlank(param.get("workerId"))) {
				sql.append(" and w.workerId =" + param.get("workerId"));
			} else if (StringUtils.isNotBlank(param.get("groupId"))) {
				sql.append(" and wg.groupId =" + param.get("groupId"));
			} else if (StringUtils.isNotBlank(param.get("deptId"))) {
				sql.append(" and gd.deptId =" + param.get("deptId"));
			}
			if (StringUtils.isNotBlank(param.get("rank"))) {
				sql.append(" and w.rank in(" + param.get("rank") + ")");
			}
			if (StringUtils.isNotBlank(param.get("type"))) {
				if (StringUtils.equals("0", param.get("type"))) {// 删除
					sql.append(" and wr.roleId =" + param.get("roleId"));
				} else if (StringUtils.equals("1", param.get("type"))) {// 新增
					sql.append(" and wr.roleId is null");
				}
			}
		}
		pager.setRowCount(baseService.getJdbcOperations().queryForLong(
				baseService.getCountSql(sql.toString())));
		sql.append(" limit ?,?");
		pager.setList(baseService.getJdbcOperations().queryForList(
				sql.toString(), pager.getRowOffset(), pager.getPageSize()));
	}

	@Override
	public List<Role> listRoleByWorkerId(Long workerId) {
		String sql = "select r.* from "
				+ TableNameUtil.getTableName(WorkerOfRole.class) + " wor join "
				+ TableNameUtil.getTableName(getClazz())
				+ " r on wor.roleId=r.roleId where workerId = ?";
		return baseService.getJdbcOperations().query(sql, rowMapper, workerId);
	}

	@Override
	public List<Map<String, Object>> listMenuOfRole(Integer roleId,
			Integer menuId) {
		String sql = "select m.menuId,m.parentId,m.menuName,r.roleId,r.roleName from"
				+ TableNameUtil.getTableName(MenuOfRole.class)
				+ " mr join "
				+ TableNameUtil.getTableName(getClazz())
				+ " m on mr.menuId=m.menuId"
				+ " join Role r on mr.roleId=r.roleId where 1=1";
		if (null != roleId) {
			sql += " and mr.roleId=" + roleId;
		}
		if (null != menuId) {
			sql += " and mr.menuId=" + menuId;
		}
		return baseService.getJdbcOperations().queryForList(sql);
	}

	@Override
	public List<Map<String, Object>> listWorkerbyRoleId(Integer roleId) {
		String fromSql = " from "
				+ TableNameUtil.getTableName(WorkerOfRole.class) + " wor join "
				+ TableNameUtil.getTableName(Worker.class)
				+ " w on wor.workerId=w.workerId " + " join "
				+ TableNameUtil.getTableName(WorkerOfGroup.class)
				+ " wog on wor.workerId=wog.workerId";

		String deptSql = "select d.deptId deptId,d.deptName deptName "
				+ fromSql + " join "
				+ TableNameUtil.getTableName(GroupOfDept.class)
				+ " god on wog.groupId=god.deptId join "
				+ TableNameUtil.getTableName(Dept.class)
				+ " d on god.deptId=d.deptId "
				+ " where wor.roleId=? group by god.deptId";
		List<Map<String, Object>> deptList = baseService.getJdbcOperations()
				.queryForList(deptSql, roleId);
		for (Map<String, Object> dept : deptList) {
			Integer deptId = (Integer) dept.get("deptId");
			String groupSql = "select g.groupId groupId,g.groupName groupName "
					+ fromSql + " join "
					+ TableNameUtil.getTableName(Group.class)
					+ " g on wog.groupId=g.groupId join "
					+ TableNameUtil.getTableName(GroupOfDept.class)
					+ " god on g.groupId=god.deptId"
					+ " where wor.roleId=? and deptId=? group by g.groupId";
			List<Map<String, Object>> groupList = baseService
					.getJdbcOperations().queryForList(groupSql, roleId, deptId);
			dept.put("subItems", groupList);
			for (Map<String, Object> group : groupList) {
				Integer groupId = (Integer) group.get("groupId");
				String workerSql = "select w.workerId workerId,w.workerName workerName "
						+ fromSql + " where wor.roleId=? and wog.groupId=? ";
				List<Map<String, Object>> workerList = baseService
						.getJdbcOperations().queryForList(workerSql, roleId,
								groupId);
				group.put("subItems", workerList);
			}
			String noDGSql = "select w.workerId workerId,w.workerName workerName  "
					+ fromSql
					+ " left join "
					+ TableNameUtil.getTableName(GroupOfDept.class)
					+ " god on wog.groupId=god.deptId"
					+ " where wor.roleId=? and god.deptId is null and wog.groupId is null";
			List<Map<String, Object>> noDGList = baseService
					.getJdbcOperations().queryForList(noDGSql, roleId);
			groupList.addAll(0, noDGList);
		}
		return deptList;
	}

	@Override
	public List<Map<String, Object>> listMenuOfRoleByRoleId(Integer roleId) {
		return listMenuOfRole(roleId, null);
	}

	@Override
	public List<Map<String, Object>> listMenuOfRoleByMenuId(Integer menuId) {
		return listMenuOfRole(null, menuId);
	}

	@Override
	public void addWorkerToRole(Integer roleId, Long[] workerIds) {
		String sql = "insert into "
				+ TableNameUtil.getTableName(WorkerOfRole.class)
				+ "(workerId,roleId) values(?,?)";
		List<Object[]> args = new ArrayList<Object[]>(workerIds.length);
		for (Long workerId : workerIds) {
			args.add(new Object[] { workerId, roleId });
		}
		baseService.getJdbcOperations().batchUpdate(sql, args);
	}

	@Override
	public void deleteWorkerFromRole(Integer roleId, Long[] workerIds) {
		String sql = "delete from "
				+ TableNameUtil.getTableName(WorkerOfRole.class)
				+ " where workerId=? and roleId=?";
		List<Object[]> args = new ArrayList<Object[]>(workerIds.length);
		for (Long workerId : workerIds) {
			args.add(new Object[] { workerId, roleId });
		}
		baseService.getJdbcOperations().batchUpdate(sql, args);
	}

	private void clearCacheByCount(int count) {
		if (count > 0) {
			baseService.clearCache(ROLE_CACHE_KEY);
		}
	}

	public Class<Role> getClazz() {
		return Role.class;
	}

	public void setBaseService(BaseService baseService) {
		this.baseService = baseService;
	}

}
